package org.oschina.api.favorite.favorite.dao;

import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.oschina.Constants;
import org.oschina.api.BaseDAO;
import org.oschina.api.favorite.favorite.model.Favorite;
import org.oschina.api.favorite.favorite.vo.FavoriteVo;
import org.oschina.api.favorite.type.dao.FavoriteTypeDAO;
import org.oschina.api.favorite.type.vo.FavoriteTypeVo;
import org.oschina.helper.cache.ICachePipeline;
import org.oschina.helper.query.IQueryCacheCallback;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

@Repository
public class FavoriteDAO extends BaseDAO {
	
	@Autowired
	private FavoriteTypeDAO favoriteTypeDAO;
	
	private final String findVo[]={"id","user","major","type"};

	private final String findVoByUserAndType="SELECT fa.id,fa.title,fa.major,fa.create_time,fat.id as 'type.id',fat.url as 'type.url' FROM "+Constants.DB_FAVORITE+" fa,"+Constants.DB_FAVORITE_TYPE+" fat WHERE fa.type=fat.id AND fa.user=? AND fa.type=? ORDER BY fa.create_time DESC LIMIT ?,?";
	
	/**
	 * 根据用户和类型返回
	 * @param user
	 * @param type
	 * @param first
	 * @param max
	 * @return
	 */
	public List<FavoriteVo> findVoByUserAndType(final int user,final int type,int first,int max)
	{
		List<FavoriteVo> result=getQueryHelper().query_cache(_findVoByUserAndTypeCache(user,type), Constants.MAX_CACHE_FAVORITE_BY_USER_AND_TYPE, first, max, FavoriteVo.class, new IQueryCacheCallback()
		{
			@Override
			public List get(int first, int max)
			{
				List<FavoriteVo> result=_findVoByUserAndType(user,type,first,max);
				for(FavoriteVo favoriteVo:result)
					setFavorite(user, favoriteVo.getMajor(), type, true);
				return result;
			}
		});
		
		if(result!=null && !result.isEmpty())
		{
			for(FavoriteVo favoriteVo:result)
			{
				favoriteVo.getType().setUrl(StringUtils.replaceEach(favoriteVo.getType().getUrl(), 
						new String[]{"{major}"},
						new String[]{favoriteVo.getMajor().toString()}));
			}
		}
		return result;
	}
	private List<FavoriteVo> _findVoByUserAndType(int user,int type,int first,int max)
	{
		return getQueryHelper().query(findVoByUserAndType,new Object[]{user,type,first,max},FavoriteVo.class);
	}
	private String _findVoByUserAndTypeCache(int user,int type)
	{
		return this.getKey(Constants.CACHE_FAVORITE_BY_USER_AND_TYPE, user,type);
	}
	private void _pushByuserAndType(int user,int type,int id)
	{
		getCacheHelper().lpush(_findVoByUserAndTypeCache(user,type), id, Constants.TIMEOUT_FAVORITE);
	}
	
	/**
	 * 根据用户和类型返回数量
	 * @param user
	 * @param type
	 * @return
	 */
	public int getCountByUserAndType(int user,int type)
	{
		String key=_getCountByUserAndTypeCache(user,type);
		Integer result=(Integer) getCacheHelper().get(key, Integer.class);
		if(result==null)
		{
			result=_getCountByUserAndType(user,type);
			getCacheHelper().set(key, result, Constants.TIMEOUT_FAVORITE);
		}
		return result;
	}
	private void _updateCountByUserAndType(int user,int type,int count)
	{
		getCacheHelper().incr(_getCountByUserAndTypeCache(user,type), count);
	}
	private int _getCountByUserAndType(int user,int type)
	{
		return (int) getQueryHelper().queryDataSum(new String[]{"user=?","type=?"}, new Object[]{user,type}, FavoriteVo.class);
	}
	private String _getCountByUserAndTypeCache(int user,int type)
	{
		return this.getKey(Constants.CACHE_FAVORITE_COUNT_BY_USER_AND_TYPE, user,type);
	}
	
	/**
	 * 根据ID返回
	 * @param id
	 * @return
	 */
	public FavoriteVo findVoById(int id)
	{
		return (FavoriteVo) getQueryHelper().queryForObject(findVo, new String[]{"id=?"}, new Object[]{id}, FavoriteVo.class);
	}
	
	/**
	 * 是否收藏
	 * @param user
	 * @param major
	 * @param type
	 * @return
	 */
	public boolean isFavorite(int user,int major,int type)
	{
		Boolean result=getCacheHelper().hexists(getCacheByUser(user), getCacheByTypeAndMajor(major, type));
		if(result==null)
		{
			result=(findIdByUserAndMajorAndType(user,major,type)!=null);
			setFavorite(user,major,type,result);
		}
		return result;
	}
	private Integer findIdByUserAndMajorAndType(int user,int major,int type)
	{
		return (Integer) getQueryHelper().queryForObject(Constants.DB_FAVORITE, new String[]{"id"}, new String[]{"user=?","major=?","type=?"}, new Object[]{user,major,type}, Integer.class);
	}
	private String getCacheByUser(int user)
	{
		return Constants.CACHE_FAVORITE+"_"+user;
	}
	private String getCacheByTypeAndMajor(int major,int type)
	{
		return major+"_"+type;
	}
	private void setFavorite(int user,int major,int type,boolean value)
	{
		getCacheHelper().hset(getCacheByUser(user), getCacheByTypeAndMajor(major,type), value, Constants.TIMEOUT_FAVORITE);
	}
	
	/**
	 * 根据用户和主键和类型删除
	 * @param user
	 * @param major
	 * @param type
	 * @return
	 */
	public int deleteByUserAndMajorAndType(int user,int major,int type)
	{
		setFavorite(user,major,type,false);
		return (int) getQueryHelper().delete(new String[]{"user=?","major=?","type=?"},new Object[]{user,major,type}, FavoriteVo.class);
	}
	
	/**
	 * 创建
	 * @param favorite
	 * @return
	 */
	public Favorite create(Favorite favorite)
	{
		getQueryHelper().insert(new String[]{"id","title","major","user","type","create_time"}, 
				new Object[]{favorite.getId(),favorite.getTitle(),favorite.getMajor(),favorite.getUser(),favorite.getType(),favorite.getCreate_time()}, FavoriteVo.class);
		
		_putCache(favorite);
		_pushByuserAndType(favorite.getUser(), favorite.getType(), favorite.getId());
		_updateCountByUserAndType(favorite.getUser(), favorite.getType(), 1);
		setFavorite(favorite.getUser(),favorite.getMajor(),favorite.getType(),true);
		
		return favorite;
	}
	
	/**
	 * 放入缓存
	 * @param favorite
	 */
	private void _putCache(Favorite favorite)
	{
		FavoriteTypeVo favorteTypeVo=favoriteTypeDAO.findVoById(favorite.getType());
		favorteTypeVo.setName(null);
		
		FavoriteVo favoriteVo=new FavoriteVo();
		
		favoriteVo.setId(favorite.getId());
		favoriteVo.setMajor(favorite.getMajor());
		favoriteVo.setTitle(favorite.getTitle());
		favoriteVo.setCreate_time(favorite.getCreate_time());
		favoriteVo.setType(favorteTypeVo);
		
		getCacheHelper().hset(_getIdKey(favorite.getId()), favoriteVo, FavoriteVo.class, Constants.TIMEOUT_FAVORITE);
	}
	
	private String _getIdKey(Object id)
	{
		return this.getKey(Constants.CACHE_FAVORITE, id);
	}
	
	/**
	 * 删除用户缓存
	 * @param user
	 */
	public void remvoeCache(int user)
	{
		ICachePipeline pipeline=getCacheHelper().getPipeline();
		List<FavoriteTypeVo> types=favoriteTypeDAO.findVo();
		for(FavoriteTypeVo type:types)
		{
			String key=_findVoByUserAndTypeCache(user, type.getId());
			List<Integer> ids=getCacheHelper().lget(key, 0, -1, Integer.class);
			for(Integer id:ids)
				pipeline.del(_getIdKey(id));
			pipeline.del(key);
			pipeline.del(_getCountByUserAndTypeCache(user, type.getId()));
		}
		pipeline.del(getCacheByUser(user));
		pipeline.sync();
	}
}